home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / DKBSRC.ARJ / TRACE.C < prev    next >
C/C++ Source or Header  |  1991-05-07  |  19KB  |  650 lines

  1. /*****************************************************************************
  2. *
  3. *                                     trace.c
  4. *
  5. *   from DKBTrace (c) 1990  David Buck
  6. *
  7. *  This module contains the entry routine for the raytracer and the code to
  8. *  parse the parameters on the command line.
  9. *
  10. *
  11. * This software is freely distributable. The source and/or object code may be
  12. * copied or uploaded to communications services so long as this notice remains
  13. * at the top of each file.  If any changes are made to the program, you must
  14. * clearly indicate in the documentation and in the programs startup message
  15. * who it was who made the changes. The documentation should also describe what
  16. * those changes were. This software may not be included in whole or in
  17. * part into any commercial package without the express written consent of the
  18. * author.  It may, however, be included in other public domain or freely
  19. * distributed software so long as the proper credit for the software is given.
  20. *
  21. * This software is provided as is without any guarantees or warranty. Although
  22. * the author has attempted to find and correct any bugs in the software, he
  23. * is not responsible for any damage caused by the use of the software.  The
  24. * author is under no obligation to provide service, corrections, or upgrades
  25. * to this package.
  26. *
  27. * Despite all the legal stuff above, if you do find bugs, I would like to hear
  28. * about them.  Also, if you have any comments or questions, you may contact me
  29. * at the following address:
  30. *
  31. *     David Buck
  32. *     22C Sonnet Cres.
  33. *     Nepean Ontario
  34. *     Canada, K2H 8W7
  35. *
  36. *  I can also be reached on the following bulleton boards:
  37. *
  38. *     OMX              (613) 731-3419
  39. *     Mystic           (613) 596-4249  or  (613) 596-4772
  40. *
  41. *  Fidonet:   1:163/109.9
  42. *  Internet:  dbuck@ccs.carleton.ca
  43. *  The "You Can Call Me RAY" BBS    (708) 358-5611
  44. *
  45. *  IBM Port by Aaron A. Collins. Aaron may be reached on the following BBS'es:
  46. *
  47. *     The "You Can Call Me RAY" BBS (708) 358-5611
  48. *     The Information Exchange BBS  (708) 945-5575
  49. *
  50. *****************************************************************************/
  51.  
  52. #include <ctype.h>
  53. #include "frame.h"        /* common to ALL modules in this program */
  54. #include "dkbproto.h"
  55.  
  56. #define MAX_FILE_NAMES 1
  57. unsigned int Options;
  58. int Quality;
  59.  
  60. FILE *bfp;
  61.  
  62. extern FRAME Frame;
  63.  
  64. char Input_File_Name[FILE_NAME_LENGTH], Output_File_Name[FILE_NAME_LENGTH];
  65.  
  66. #define MAX_LIBRARIES 10
  67. char *Library_Paths[MAX_LIBRARIES];
  68. int Library_Path_Index;
  69.  
  70. FILE_HANDLE *Output_File_Handle;
  71. int File_Buffer_Size;
  72. static int Number_Of_Files;
  73. DBL VTemp;
  74. DBL Antialias_Threshold;
  75. int First_Line, Last_Line;
  76. int Display_Started = FALSE;
  77.  
  78. /* Stats kept by the ray tracer: */
  79. long Number_Of_Pixels, Number_Of_Rays, Number_Of_Pixels_Supersampled;
  80. long Ray_Sphere_Tests, Ray_Sphere_Tests_Succeeded;
  81. long Ray_Plane_Tests, Ray_Plane_Tests_Succeeded;
  82. long Ray_Triangle_Tests, Ray_Triangle_Tests_Succeeded;
  83. long Ray_Quadric_Tests, Ray_Quadric_Tests_Succeeded;
  84. long Ray_Quartic_Tests, Ray_Quartic_Tests_Succeeded;
  85. long Bounding_Region_Tests, Bounding_Region_Tests_Succeeded;
  86. long Calls_To_Noise, Calls_To_DNoise;
  87. long Shadow_Ray_Tests, Shadow_Rays_Succeeded;
  88. long Reflected_Rays_Traced, Refracted_Rays_Traced;
  89. long Transmitted_Rays_Traced;
  90.  
  91. char DisplayFormat, OutputFormat;
  92.  
  93. void main (argc, argv)
  94.   int argc;
  95.   char **argv;
  96.   {
  97.   register int i;
  98.  
  99.   STARTUP_DKB_TRACE
  100.  
  101.   printf ("\n\n          DKB Ray Trace   Version 2.12\n");
  102.   printf ("          ----------------------------\n\n");
  103.   printf ("        Copyright (c) 1991  David K. Buck\n\n");
  104.   printf ("  Written by:\n");
  105.   printf ("  David K. Buck (dbuck@ccs.carleton.ca) (CIS: 70521, 1371)\n");
  106.   printf ("  22C Sonnet Cr.  Nepean, Ontario\n");
  107.   printf ("  Canada, K2H 8W7\n\n");
  108.   printf ("  This program is freely distributable.\n\n");
  109.  
  110.   printf ("  Conversion to IBM P.C. w/TARGA output and\n");
  111.   printf ("  other various improvements by Aaron A. Collins\n\n");
  112.  
  113.   printf ("  GIF format file reader by Steve A. Bennett\n\n");
  114.  
  115.   printf ("  Noise and DNoise functions by Robert Skinner\n\n");
  116.  
  117.   printf ("  Quartic (4th order) Shapes by Alexander Enzmann\n\n");
  118.  
  119.   PRINT_OTHER_CREDITS
  120.  
  121. /* Parse the command line parameters */
  122.   if (argc == 1)
  123.      usage();
  124.  
  125.   init_vars();
  126.  
  127.   Output_File_Name[0]='\0';
  128.  
  129.   Library_Paths[0] = NULL;
  130.   Library_Path_Index = 0;
  131.  
  132. /* Read the default parameters from trace.def */
  133.   get_defaults();
  134.  
  135.   for (i = 1 ; i < argc ; i++ )
  136.     if ((*argv[i] == '+') || (*argv[i] == '-'))
  137.       parse_option(argv[i]);
  138.     else
  139.       parse_file_name(argv[i]);
  140.  
  141.    if (Last_Line == -1)
  142.       Last_Line = Frame.Screen_Height;
  143.  
  144.    if (Options & DISKWRITE) {
  145.       switch (OutputFormat) {
  146.          case '\0':
  147.          case 'd':
  148.          case 'D':
  149.                    if ((Output_File_Handle = Get_Dump_File_Handle()) == NULL) {
  150.                       close_all();
  151.                       exit(1);
  152.                       }
  153.                    break;
  154. /*
  155.          case 'i':
  156.          case 'I':
  157.                    if ((Output_File_Handle = Get_Iff_File_Handle()) == NULL) {
  158.                       close_all();
  159.                       exit(1);
  160.                       }
  161.                    break;
  162.  
  163. */
  164.          case 'r':
  165.          case 'R':
  166.                    if ((Output_File_Handle = Get_Raw_File_Handle()) == NULL) {
  167.                       close_all();
  168.                       exit(1);
  169.                       }
  170.                    break;
  171.  
  172.          case 't':
  173.          case 'T':
  174.                    if ((Output_File_Handle = Get_Targa_File_Handle()) == NULL) {
  175.                       close_all();
  176.                       exit(1);
  177.                       }
  178.                    break;
  179.  
  180.          default:
  181.                    fprintf (stderr, "Unrecognized output file format %c\n", OutputFormat);
  182.                    exit(1);
  183.          }
  184.  
  185.       if (Output_File_Name[0] == '\0')
  186.          strcpy (Output_File_Name, Default_File_Name (Output_File_Handle));
  187.       }
  188.  
  189.    Print_Options();
  190.  
  191.    Initialize_Tokenizer(Input_File_Name);
  192.    printf ("Parsing...\n");
  193.    Parse (&Frame);
  194.    Terminate_Tokenizer();
  195.  
  196.   if (Options & DISPLAY)
  197.     {
  198.     printf ("Displaying...\n");
  199.     display_init(Frame.Screen_Width, Frame.Screen_Height);
  200.     Display_Started = TRUE;
  201.     }
  202.  
  203. /* Get things ready for ray tracing */
  204.    if (Options & DISKWRITE)
  205.       if (Options & CONTINUE_TRACE) {
  206.          if (Open_File (Output_File_Handle, Output_File_Name,
  207.                  &Frame.Screen_Width, &Frame.Screen_Height, File_Buffer_Size,
  208.                  READ_MODE) != 1) {
  209.             fprintf (stderr, "Error opening output file\n");
  210.             close_all();
  211.             exit(1);
  212.             }
  213.  
  214.          initialize_renderer();
  215.          Read_Rendered_Part();
  216.          }
  217.       else {
  218.          if (Open_File (Output_File_Handle, Output_File_Name,
  219.                  &Frame.Screen_Width, &Frame.Screen_Height, File_Buffer_Size,
  220.                  WRITE_MODE) != 1) {
  221.             fprintf (stderr, "Error opening output file\n");
  222.             close_all();
  223.             exit(1);
  224.             }
  225.  
  226.          initialize_renderer();
  227.          }
  228.   else
  229.      initialize_renderer();
  230.  
  231.   pq_init();
  232.   Initialize_Noise();
  233.  
  234. /* Ok, go for it - trace the picture */
  235.   if (!(Options & DISPLAY))
  236.       printf ("Rendering...\n");
  237.   Start_Tracing ();
  238.  
  239. /* Wait for a CR if the user requested it. */
  240.  
  241. /* Clean up and leave */
  242.   display_finished();
  243.  
  244.   close_all ();
  245.   print_stats();
  246.  
  247.   FINISH_DKB_TRACE
  248.   }
  249.  
  250. /* Print out usage error message */
  251.  
  252. void usage ()
  253.     {
  254.     printf ("\nUsage:");
  255.     printf ("\n   trace  [+/-] Option1 [+/-] Option2");
  256.     printf ("\n");
  257.     printf ("\n Options:");
  258.     printf ("\n    dx = display in format x");
  259.     printf ("\n    v  = verbose");
  260.     printf ("\n    p  = prompt exit");
  261.     printf ("\n    x  = enable early exit by key hit");
  262.     printf ("\n    fx = write output file in format x");
  263.     printf ("\n         ft - Uncompressed Targa-24  fd - DKB/QRT Dump  fr - 3 Raw Files");
  264.     printf ("\n    a  = perform antialiasing");
  265.     printf ("\n    c  = continue aborted trace");
  266.     printf ("\n    qx = image quality 0=rough, 9=full");
  267.     printf ("\n    lxxx = library path prefix");
  268.     printf ("\n    wxxx = width of the screen");
  269.     printf ("\n    hxxx = height of the screen");
  270.     printf ("\n    sxxx = start at line number xxx");
  271.     printf ("\n    exxx = end at line number xxx");
  272.     printf ("\n    bxxx = Use xxx kilobytes for output file buffer space");
  273.     printf ("\n    ifilename = input file name");
  274.     printf ("\n    ofilename = output file name");
  275.     printf ("\n\n");
  276.     exit(1);
  277.     }
  278.  
  279. void init_vars()
  280.   {
  281.   Output_File_Handle = NULL;
  282.   File_Buffer_Size = 0;
  283.   Options = 0;
  284.   Quality = 9;
  285.   Number_Of_Files = 0;
  286.   First_Line = 0;
  287.   Last_Line = -1;
  288.  
  289.   Number_Of_Pixels = 0L;
  290.   Number_Of_Rays = 0L;
  291.   Number_Of_Pixels_Supersampled = 0L;
  292.   Ray_Sphere_Tests = 0L;
  293.   Ray_Sphere_Tests_Succeeded = 0L;
  294.   Ray_Plane_Tests = 0L;
  295.   Ray_Plane_Tests_Succeeded = 0L;
  296.   Ray_Triangle_Tests = 0L;
  297.   Ray_Triangle_Tests_Succeeded = 0L;
  298.   Ray_Quadric_Tests = 0L;
  299.   Ray_Quadric_Tests_Succeeded = 0L;
  300.   Ray_Quartic_Tests = 0L;
  301.   Ray_Quartic_Tests_Succeeded = 0L;
  302.   Bounding_Region_Tests = 0L;
  303.   Bounding_Region_Tests_Succeeded = 0L;
  304.   Calls_To_Noise = 0L;
  305.   Calls_To_DNoise = 0L;
  306.   Shadow_Ray_Tests = 0L;
  307.   Shadow_Rays_Succeeded = 0L;
  308.   Reflected_Rays_Traced = 0L;
  309.   Refracted_Rays_Traced = 0L;
  310.   Transmitted_Rays_Traced = 0L;
  311.  
  312.   Frame.Screen_Height = 100;
  313.   Frame.Screen_Width = 100;
  314.  
  315.   Antialias_Threshold = 0.3;
  316.   strcpy (Input_File_Name, "object.dat");
  317.   return;
  318.   }
  319.  
  320. /* Close all the stuff that has been opened. */
  321. void close_all ()
  322.    {
  323.    if ((Options & DISPLAY) && Display_Started)
  324.      display_close();
  325.  
  326.    if (Output_File_Handle)
  327.       Close_File (Output_File_Handle);
  328.    }
  329.  
  330. /* Read the default parameters from trace.def*/
  331. void get_defaults()
  332.   {
  333.   FILE *defaults_file;
  334.   char Option_String[256], *Option_String_Ptr;
  335.  
  336.   if ((defaults_file = fopen("trace.def", "r")) != NULL) {
  337.      while (fgets(Option_String, 256, defaults_file) != NULL)
  338.         read_options(Option_String);
  339.      fclose (defaults_file);
  340.      }
  341.  
  342.   if ((Option_String_Ptr = getenv("DKBOPT")) != NULL)
  343.      read_options(Option_String_Ptr);
  344.   }
  345.  
  346. void read_options (Option_Line)
  347.   char *Option_Line;
  348.   {
  349.   register int c, String_Index, Option_Started;
  350.   short Option_Line_Index = 0;
  351.   char Option_String[80];
  352.  
  353.   String_Index = 0;
  354.   Option_Started = FALSE;
  355.   while ((c = Option_Line[Option_Line_Index++]) != '\0')
  356.     {
  357.     if (Option_Started)
  358.       if (isspace(c))
  359.         {
  360.         Option_String[String_Index] = '\0';
  361.         parse_option (Option_String);
  362.         Option_Started = FALSE;
  363.     String_Index = 0;
  364.         }
  365.      else
  366.        Option_String[String_Index++] = (char) c;
  367.  
  368.     else /* Option_Started */
  369.       if ((c == (int) '-') || (c == (int) '+'))
  370.         {
  371.         String_Index = 0;
  372.         Option_String[String_Index++] = (char) c;
  373.         Option_Started = TRUE;
  374.         }
  375.       else
  376.         if (!isspace(c))
  377.           {
  378.           fprintf (stderr, "\nBad default file format.  Offending char: (%c), val: %d.\n", (char) c, c);
  379.           exit (1);
  380.           }
  381.     }
  382.  
  383.   if (Option_Started)
  384.     {
  385.     Option_String[String_Index] = '\0';
  386.     parse_option (Option_String);
  387.     }
  388.   }
  389.  
  390. /* parse the command line parameters */
  391. void parse_option (Option_String)
  392.   char *Option_String;
  393.   {
  394.   register int Add_Option;
  395.   unsigned int Option_Number;
  396.   DBL threshold;
  397.  
  398.   if (*(Option_String++) == '-')
  399.     Add_Option = FALSE;
  400.   else
  401.     Add_Option = TRUE;
  402.  
  403.   switch (*Option_String)
  404.     {
  405.     case 'B':
  406.     case 'b':  sscanf (&Option_String[1], "%d", &File_Buffer_Size);
  407.                File_Buffer_Size *= 1024;
  408.                if (File_Buffer_Size < BUFSIZ)
  409.                   File_Buffer_Size = BUFSIZ;
  410.                Option_Number = 0;
  411.                break;
  412.  
  413.     case 'C':
  414.     case 'c':  Option_Number = CONTINUE_TRACE;
  415.                break;
  416.  
  417.     case 'D':
  418.     case 'd':  Option_Number = DISPLAY;
  419.                DisplayFormat = (char)toupper(Option_String[1]);
  420.                if (DisplayFormat == '\0')
  421.                   DisplayFormat = '0';
  422.                break;
  423.  
  424.     case 'V':
  425.     case 'v':  Option_Number = VERBOSE;
  426.                break;
  427.  
  428.     case 'W':
  429.     case 'w':  sscanf (&Option_String[1], "%d", &Frame.Screen_Width);
  430.            Option_Number = 0;
  431.                break;
  432.  
  433.     case 'H':
  434.     case 'h':  sscanf (&Option_String[1], "%d", &Frame.Screen_Height);
  435.            Option_Number = 0;
  436.                break;
  437.  
  438.     case 'F':
  439.     case 'f':  Option_Number = DISKWRITE;
  440.                if (isupper(Option_String[1]))
  441.                   OutputFormat = (char)tolower(Option_String[1]);
  442.                else
  443.                   OutputFormat = Option_String[1];
  444.  
  445.                /* Default the output format to raw. */
  446.                if (OutputFormat == '\0')
  447.                   OutputFormat = DEFAULT_OUTPUT_FORMAT;
  448.                break;
  449.  
  450.     case 'P':
  451.     case 'p':  Option_Number = PROMPTEXIT;
  452.                break;
  453.  
  454.     case 'I':
  455.     case 'i':  strncpy (Input_File_Name, &Option_String[1], FILE_NAME_LENGTH);
  456.            Option_Number = 0;
  457.                break;
  458.  
  459.     case 'O':
  460.     case 'o':  strncpy (Output_File_Name, &Option_String[1], FILE_NAME_LENGTH);
  461.            Option_Number = 0;
  462.                break;
  463.  
  464.     case 'A':
  465.     case 'a':  Option_Number = ANTIALIAS;
  466.                if (sscanf (&Option_String[1], DBL_FORMAT_STRING, &threshold) != EOF)
  467.                    Antialias_Threshold = threshold;
  468.                break;
  469.  
  470.     case 'X':
  471.     case 'x':  Option_Number = EXITENABLE;
  472.                break;
  473.  
  474.  
  475.     case 'L':
  476.     case 'l':  if (Library_Path_Index >= MAX_LIBRARIES) {
  477.                   fprintf (stderr, "Too many library directories specified\n");
  478.                   exit(1);
  479.                   }
  480.  
  481.                Library_Paths [Library_Path_Index] = malloc (strlen(Option_String));
  482.            if (Library_Paths [Library_Path_Index] == NULL) {
  483.           fprintf (stderr, "Cannot allocate memory for library pathname\n");
  484.           exit(1);
  485.           }
  486.                strcpy (Library_Paths [Library_Path_Index], &Option_String[1]);
  487.                Library_Path_Index++;
  488.            Option_Number = 0;
  489.                break;
  490.  
  491.     case 'S':
  492.     case 's':  sscanf (&Option_String[1], "%d", &First_Line);
  493.            Option_Number = 0;
  494.                break;
  495.  
  496.     case 'E':
  497.     case 'e':  sscanf (&Option_String[1], "%d", &Last_Line);
  498.            Option_Number = 0;
  499.                break;
  500.  
  501.     case 'Q':
  502.     case 'q':  sscanf (&Option_String[1], "%d", &Quality);
  503.            Option_Number = 0;
  504.                break;
  505.  
  506.                /* Turn on debugging print statements. */
  507.     case 'Z':
  508.     case 'z':  Option_Number = DEBUGGING;
  509.                break;
  510.  
  511.     default:   fprintf (stderr, "\nInvalid option: %s\n\n", --Option_String);
  512.            Option_Number = 0;
  513.     }
  514.  
  515.   if (Option_Number != 0)
  516.       if (Add_Option)
  517.            Options |= Option_Number;
  518.       else Options &= ~Option_Number;
  519.   }
  520.  
  521. void Print_Options()
  522.    {
  523.    int i;
  524.  
  525.    printf ("Options in effect: ");
  526.  
  527.    if (Options & CONTINUE_TRACE)
  528.       printf ("+c ");
  529.    else
  530.       printf ("-c ");
  531.  
  532.    if (Options & DISPLAY)
  533.       printf ("+d%c ", DisplayFormat);
  534.    else
  535.       printf ("-d ");
  536.  
  537.    if (Options & VERBOSE)
  538.       printf ("+v ");
  539.    else
  540.       printf ("-v ");
  541.  
  542.    if (Options & DISKWRITE)
  543.       printf ("+f%c ", OutputFormat);
  544.    else
  545.       printf ("-f ");
  546.  
  547.    if (Options & PROMPTEXIT)
  548.       printf ("+p ");
  549.    else
  550.       printf ("-p ");
  551.  
  552.    if (Options & EXITENABLE)
  553.       printf ("+x ");
  554.    else
  555.       printf ("-x ");
  556.  
  557.    if (Options & ANTIALIAS)
  558.       printf ("+a%f ", Antialias_Threshold);
  559.    else
  560.       printf ("-a ");
  561.  
  562.    if (Options & DEBUGGING)
  563.       printf ("+z ");
  564.  
  565.    if (File_Buffer_Size != 0)
  566.       printf ("-b%d ", File_Buffer_Size/1024);
  567.  
  568.    printf ("-q%d -w%d -h%d -s%d -e%d\n-i%s ",
  569.            Quality, Frame.Screen_Width, Frame.Screen_Height,
  570.            First_Line, Last_Line, Input_File_Name);
  571.  
  572.    if (Options & DISKWRITE)
  573.       printf ("-o%s ", Output_File_Name);
  574.  
  575.    for (i = 0 ; i < Library_Path_Index ; i++)
  576.       printf ("-l%s ", Library_Paths[i]);
  577.  
  578.    printf ("\n");
  579.    }
  580.  
  581. void parse_file_name (File_Name)
  582.   char *File_Name;
  583.   {
  584.   FILE *defaults_file;
  585.   char Option_String[256];
  586.  
  587.   if (++Number_Of_Files > MAX_FILE_NAMES)
  588.     {
  589.     fprintf (stderr, "\nOnly %d file names are allowed in a command line.", 
  590.              MAX_FILE_NAMES);
  591.     exit(1);
  592.     }
  593.  
  594.   if ((defaults_file = fopen(File_Name, "r")) != NULL) {
  595.      while (fgets(Option_String, 256, defaults_file) != NULL)
  596.         read_options(Option_String);
  597.      fclose (defaults_file);
  598.      }
  599.   }
  600.  
  601. void print_stats()
  602.    {
  603.    printf ("                  Statistics\n");
  604.    printf ("                  ----------\n\n");
  605.    printf ("# Rays:  %10ld    # Pixels:  %10ld  # Pixels supersampled: %10ld\n\n",
  606.             Number_Of_Rays, Number_Of_Pixels, Number_Of_Pixels_Supersampled);
  607.  
  608.    printf ("\nIntersection Tests:\n\n");
  609.    printf ("   Type       Tests    Succeeded\n");
  610.    printf ("   ----    ----------  ----------\n\n");
  611.    printf ("  Sphere   %10ld  %10ld\n", Ray_Sphere_Tests, Ray_Sphere_Tests_Succeeded);
  612.    printf ("  Plane    %10ld  %10ld\n", Ray_Plane_Tests, Ray_Plane_Tests_Succeeded);
  613.    printf ("  Triangle %10ld  %10ld\n", Ray_Triangle_Tests, Ray_Triangle_Tests_Succeeded);
  614.    printf ("  Quadric  %10ld  %10ld\n", Ray_Quadric_Tests, Ray_Quadric_Tests_Succeeded);
  615.    printf ("  Quartic  %10ld  %10ld\n", Ray_Quartic_Tests, Ray_Quartic_Tests_Succeeded);
  616.    printf ("  Bounds   %10ld  %10ld\n\n", Bounding_Region_Tests, Bounding_Region_Tests_Succeeded);
  617.    printf ("  Calls to Noise:   %10ld\n", Calls_To_Noise);
  618.    printf ("  Calls to DNoise:  %10ld\n", Calls_To_DNoise);
  619.    printf ("  Shadow Ray Tests: %10ld     Blocking Objects Found:  %10ld\n",
  620.               Shadow_Ray_Tests, Shadow_Rays_Succeeded);
  621.    printf ("  Reflected Rays:   %10ld\n", Reflected_Rays_Traced);
  622.    printf ("  Refracted Rays:   %10ld\n", Refracted_Rays_Traced);
  623.    printf ("  Transmitted Rays: %10ld\n", Transmitted_Rays_Traced);
  624.    }
  625.  
  626. /* Find a file in the search path. */
  627.  
  628. FILE *Locate_File (filename, mode)
  629.    char *filename, *mode;
  630.    {
  631.    FILE *f;
  632.    int i;
  633.    char pathname[FILE_NAME_LENGTH];
  634.  
  635.    /* Check the current directory first. */
  636.    if ((f = fopen (filename, mode)) != NULL)
  637.       return (f);
  638.  
  639.    for (i = 0 ; i < Library_Path_Index ; i++) {
  640.       strcpy (pathname, Library_Paths[i]);
  641.       if (FILENAME_SEPARATOR != NULL)
  642.          strcat (pathname, FILENAME_SEPARATOR);
  643.       strcat (pathname, filename);
  644.       if ((f = fopen (pathname, mode)) != NULL)
  645.          return (f);
  646.       }
  647.  
  648.    return (NULL);
  649.    }
  650.